﻿using System;
using System.Collections.Generic;

namespace FlyweightPattern;

// 抽象享元接口
public abstract class FileResource
{
    public abstract void Display(UserFileContext context);
}

// 具体享元，包含可共享的内部状态
public class SharedFileResource(string name, string url, long size) : FileResource
{
    public override void Display(UserFileContext context)
    {
        Console.WriteLine(
            $"文件名称: {name}\n大小: {size}B\nURL: {url}\n位置: {context.Location}\n访问权限: {(context.IsPublic ? "公开" : "私有")}\n");
    }
}

// 不可共享的上下文，包含用户特定的外部状态
public class UserFileContext(string location, bool isPublic)
{
    public string Location { get; } = location;
    public bool IsPublic { get; } = isPublic;
}

// 享元工厂，用于管理享元对象
public class FileResourceFactory
{
    private readonly Dictionary<string, SharedFileResource> _flyweights = new();

    public FileResource GetFileResource(string name, string url, long size)
    {
        var key = $"{name}/{url}/{size}";
        if (_flyweights.TryGetValue(key, out var resource)) return resource;
        resource = new SharedFileResource(name, url, size);
        _flyweights.Add(key, resource);

        return resource;
    }
}

public static class Program
{
    public static void Main()
    {
        var factory = new FileResourceFactory();

        var context1 = new UserFileContext("/user1/Files", false);
        var file1 = factory.GetFileResource("File1.pdf", "https://S-Pan.com/file1.pdf", 1024);
        file1.Display(context1);

        var context2 = new UserFileContext("/user2/Doc", true);
        var file2 = factory.GetFileResource("File1.pdf", "https://S-Pan.com/file1.pdf",
            1024); // 由于URL等信息相同，将返回相同的享元实例
        file2.Display(context2);

        var context3 = new UserFileContext("/user3/Downloads", false);
        var file3 = factory.GetFileResource("File2.pdf", "https://S-Pan.com/file2.pdf", 2048);
        file3.Display(context3);
        
        Console.WriteLine("\n验证可共享享元的正确性");
        Console.WriteLine(ReferenceEquals(file1,file2));
        Console.WriteLine(ReferenceEquals(file1,file3));
    }
}
